package com.zsrt.devbase.common.utils.mail;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;

import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.zsrt.devbase.common.utils.ConstantDefine;
import com.zsrt.devbase.common.utils.DateUtil;
import com.zsrt.devbase.common.utils.MailConstantDefine;
import com.zsrt.devbase.common.utils.MsgConstantConfig;
import com.zsrt.devbase.common.utils.StringUtil;
import com.zsrt.devbase.dto.EmailAttachDTO;
import com.zsrt.devbase.dto.EmailLogDTO;

import freemarker.template.Template;
import freemarker.template.TemplateException;

/** 
 * @author leixin  
 * @Email leixin821792669@gmail.com
 * @date 2018年7月7日 下午8:03:07
 * @version 1.0
 */
public class SendMailHelper implements Callable<EmailLogDTO>{
	//必填
	private final EmailLogDTO dto;
	//是否开启免后缀模式
	private final Boolean useAppender;
	private final MailConfig config;
	
	private FreeMarkerConfigurer freeMarker;
	private String mailAppender = MailConstantDefine.DEFAULT_MAIL_APPENDER;

	@Override
	public EmailLogDTO call() throws Exception {
		HtmlEmail htmlEmail = getMailConfig(config);
		return this.send(this.dto,htmlEmail);
	}
	
	
	/**
	 * 发送邮件方法
	 * @author leixin
	 * @date 2018年7月8日
	 * @param dto
	 * @param email
	 * @return
	 */
	private EmailLogDTO send(EmailLogDTO dto,HtmlEmail email) {
		if (null == dto) {
			return null;
		}
		if (null == email) {
			//收件人空
			dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
			dto.setErrorMsg("发件箱错误");
			setUpd(dto);
			return dto;
		}
		if (null == dto.getToList()) {
			//收件人空
			dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
			dto.setErrorMsg("收件人为空");
			setUpd(dto);
			return dto;
		}
		//设置收件人
		for(int i = 0 ; i< String2AddressList(dto.getToList()).size() ; i++) {
			EmailAddr address = null ;
			try {
				address = String2AddressList(dto.getToList()).get(i);
				email.addTo(address.getAddress(),address.getName());
			} catch (EmailException | IndexOutOfBoundsException  e ) {
				dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
				if (e instanceof IndexOutOfBoundsException) {
					dto.setErrorMsg(MailConstantDefine.TO_ADDRESS_ERROR);
				} else {
					dto.setErrorMsg(MailConstantDefine.TO_ADDRESS_ERROR+address.getAddress());
				}
				setUpd(dto);
				if (i == 0) {
					return dto;
				}
			}
		}
		//设置抄送
		List<EmailAddr> ccAddressList = String2AddressList(dto.getCcList());
		if (!CollectionUtils.isEmpty(ccAddressList)) {
			for(EmailAddr address : ccAddressList) {
				try {
					email.addTo(address.getAddress(),address.getName());
				} catch (EmailException e) {
					dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
					dto.setErrorMsg(MailConstantDefine.CC_ADDRESS_ERROR+address.getAddress());
					setUpd(dto);
				}
			}
		}
		
		if (!StringUtil.isEmpty(dto.getSubject())) {
			email.setSubject(dto.getSubject());
		}else {
			email.setSubject(MailConstantDefine.DEFAULT_SUBJECT);
		}
		//设置邮件内容
		try {
			setContext(dto,email);
		} catch (MalformedURLException | EmailException | JSONException e) {
			dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
			setUpd(dto);
			if (e instanceof JSONException) {
				dto.setErrorMsg(MailConstantDefine.MAIL_JSON_CONVERT_ERROR);
			}else {
				dto.setErrorMsg(MailConstantDefine.MAIL_CONTENT_ERROR);
			}
			return dto;
			
		}	
		//发送邮件
		try {
			email.send();
		} catch (EmailException e) {
			dto.setIsSended(MailConstantDefine.MESSAGE_SEND_ERROR);
			dto.setErrorMsg(MailConstantDefine.MAIL_SEND_ERROR);
			setUpd(dto);
			return dto;
		}
		dto.setIsSended(MailConstantDefine.MESSAGE_SEND_SUCCESS);
		setUpd(dto);
		return dto;
		
	}
	/**
	 * 初始化邮件配置
	 * @author leixin
	 * @date 2018年7月8日
	 * @param config
	 * @param htmlEmail
	 * @return
	 */
	private HtmlEmail getMailConfig(MailConfig config) {
		HtmlEmail htmlEmail = new HtmlEmail();
		if (null != config.getPassword()) {
			htmlEmail.setAuthentication(config.getFormAddr(), config.getPassword());
		}
		try {
			htmlEmail.setFrom(getRealAddress(config.getFormAddr()), config.getFormName());
		} catch (EmailException e) {
			htmlEmail = null;
			return null;
		}
		htmlEmail.setSmtpPort(config.getSmtpPort());
		htmlEmail.setHostName(config.getHostName());
		htmlEmail.setSSLOnConnect(config.getSslOnConnect());
		return htmlEmail;
	}
	
	private void setContext(EmailLogDTO dto, HtmlEmail email) throws MalformedURLException ,EmailException, JSONException{
		String content = dto.getContent();
		if (dto.getEmailType() == MsgConstantConfig.EmailType.SIMPLE.getValue()) {
			email.setMsg(content);
		}else if (MsgConstantConfig.EmailType.WITH_ATTACHMENT.getValue() == dto.getEmailType()) {
			//判断是否使用模板
			if ("1".equals(dto.getUseTemplate())) {
				String mailText = getMailText(content,dto.getTemplateId());
				//如果获取的内容为空，则直接设置content
				if ("".equals(mailText)) {
					email.setMsg(content);
				} else {
					email.setMsg(mailText);	
				}
			} else {
				email.setMsg(content);
			}
			//获取附件
			if (null != dto.getEmailAttach()) {
				EmailAttachment attachment = null;
				for(EmailAttachDTO attachDTO : dto.getEmailAttach()) {
					attachment = new EmailAttachment();
					attachment.setName(attachDTO.getName());
					attachment.setDescription(attachDTO.getDescription());
					attachment.setPath(attachDTO.getUrl());
				}
			}
		} else if (MsgConstantConfig.EmailType.HTML.getValue() == dto.getEmailType()) {
			email.setHtmlMsg(content);
		} else {
			email.setHtmlMsg(content);
			//邮件类型不支持
			email.setTextMsg(MailConstantDefine.MAIL_TEXT_MESSAGE);
		}
	}

	/**
	 * 读取模板内容发送邮件
	 * @author leixin
	 * @date 2018年7月8日
	 * @param content
	 * @param templateId
	 * @return
	 * @throws JSONException
	 */
	@SuppressWarnings("unchecked")
	private String getMailText(String content, String templateId) throws JSONException{
		HashMap<String, Object> mapObj = null;
		mapObj = JSONObject.parseObject(content,HashMap.class);
		Template template = null;
		String htmlText = null;
		try {
			template = freeMarker.getConfiguration().getTemplate(templateId);
			htmlText = FreeMarkerTemplateUtils.processTemplateIntoString(template, mapObj);
		} catch (IOException | TemplateException e) {
			
		} 
		return htmlText;
	}

	private void setUpd(EmailLogDTO dto) {
		dto.setModifyTime(DateUtil.getSystemTimeStr());
		dto.setModifier(ConstantDefine.SYSTEM);
	}
	
	private String getRealAddress(String address) {
		if (this.useAppender) {
			return address+"@"+mailAppender;
		}
		return address;
	}
	private List<EmailAddr> String2AddressList(String addressListString){
		List<EmailAddr> emailAddressList = new ArrayList<>();
		if (!StringUtil.isEmpty(addressListString)) {
			String[] addressArr = addressListString.split(";");
			EmailAddr emailAddress;
			try {
				for (int i = 0; i < addressArr.length; i++) {
					if (this.useAppender) {
						emailAddress = new EmailAddr(addressArr[i]+"@"+this.mailAppender, addressArr[i]);
						emailAddressList.add(emailAddress);
					}else {
						emailAddress = new EmailAddr(addressArr[i], addressArr[i]);
						emailAddressList.add(emailAddress);
					}
				}
			} catch (IndexOutOfBoundsException e) {
				return emailAddressList;
			}
		}
		return emailAddressList;
	}
	
	
	public static class MailBuilder{
		private final EmailLogDTO dto;
		private final Boolean useAppender;
		private final MailConfig config;
		private FreeMarkerConfigurer freeMarker;
		private String mailAppender = MailConstantDefine.DEFAULT_MAIL_APPENDER;
		
		public MailBuilder(EmailLogDTO dto,Boolean useAppender,MailConfig config) {
			this.dto = dto;
			this.useAppender = useAppender;
			this.config = config;
		}
		public MailBuilder freeMarker(FreeMarkerConfigurer freeMarker) {
			this.freeMarker = freeMarker;
			return this;
		}
		public MailBuilder mailAppender(String mailAppender) {
			this.mailAppender = mailAppender;
			return this;
		}
		
		public SendMailHelper build() {
			return new SendMailHelper(this);
		}
	}
	/**
	 * 私有构造方法
	 * @param builder
	 */
	private SendMailHelper(MailBuilder builder) {
		this.config = builder.config;
		this.dto = builder.dto;
		this.freeMarker = builder.freeMarker;
		this.mailAppender = builder.mailAppender;
		this.useAppender = builder.useAppender;
	}
}
